package com.significantfiles.snapshot.engine.rt;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;

import com.significantfiles.snapshot.engine.compiler.EntityInterfaceParser;
import com.significantfiles.snapshot.engine.compiler.model.x.EntityInterfaceIsBrokenException;
import com.significantfiles.snapshot.engine.structure.id.EntityIdFactory;

public class EntityFactory {

	private final EntityInterfaceParser parser = new EntityInterfaceParser();
	
	private final EntityIdFactory idFactory;

	public EntityFactory(final EntityIdFactory idFactory) {
		this.idFactory = idFactory;
	}

	public void registerModelInterface(Class<?> modelInterface)
			throws EntityInterfaceIsBrokenException {
		parser.parse(modelInterface);
	}

	public <T> T createInstance(final Class<T> modelItf)
			throws EntityInterfaceIsBrokenException {
		if (modelItf == null)
			throw new NullPointerException();

		final Class<T> impl = this.parser.get(modelItf);

		try {
			final Constructor<T> constructor = impl.getConstructor(
					BigInteger.class, long.class );
			
			return constructor.newInstance(calcId(), calcCreatedAt());
		} catch (final SecurityException e) {
			throw new EntityInterfaceIsBrokenException();
		} catch (final NoSuchMethodException e) {
			throw new EntityInterfaceIsBrokenException();
		} catch (IllegalArgumentException e) {
			throw new EntityInterfaceIsBrokenException();
		} catch (InstantiationException e) {
			throw new EntityInterfaceIsBrokenException();
		} catch (IllegalAccessException e) {
			throw new EntityInterfaceIsBrokenException();
		} catch (InvocationTargetException e) {
			throw new EntityInterfaceIsBrokenException();
		}
	}

	private BigInteger calcId() {
		return this.idFactory.createNewId();
	}

	private long calcCreatedAt() {
		return System.currentTimeMillis();
	}

}
